package shop.kundenverwaltung.rest; import static shop.util.Constants.ADD_LINK; import static shop.util.Constants.FIRST_LINK; import static shop.util.Constants.KEINE_ID; import static shop.util.Constants.LAST_LINK; import static shop.util.Constants.LIST_LINK; import static shop.util.Constants.REMOVE_LINK; import static shop.util.Constants.SELF_LINK; import static shop.util.Constants.UPDATE_LINK; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.MediaType.APPLICATION_XML; import static javax.ws.rs.core.MediaType.TEXT_PLAIN; import static javax.ws.rs.core.MediaType.TEXT_XML; import java.lang.invoke.MethodHandles; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.transaction.Transactional; import javax.validation.Valid; import javax.validation.constraints.Pattern; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.GenericEntity; import javax.ws.rs.core.Link; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import org.hibernate.validator.constraints.Email; import org.jboss.logging.Logger; import com.google.common.base.Strings; import shop.bestellverwaltung.domain.Bestellung; import shop.bestellverwaltung.rest.BestellungResource; import shop.bestellverwaltung.service.BestellungService; import shop.kundenverwaltung.domain.AbstractKunde; import shop.kundenverwaltung.domain.Adresse; import shop.kundenverwaltung.domain.Bankdaten; import shop.kundenverwaltung.service.KundenService; import shop.kundenverwaltung.service.KundenService.FetchType; import shop.kundenverwaltung.service.KundenService.OrderType; import shop.util.interceptor.Log; import shop.util.rest.UriHelper; @Path("/kunden") @Produces({ APPLICATION_JSON, APPLICATION_XML + ";qs=0.75", TEXT_XML + ";qs=0.5" }) @Consumes @RequestScoped @Transactional @Log public class KundeResource { private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass()); private static final String VERSION = "1.0"; public static final String KUNDEN_ID_PATH_PARAM = "kundeId"; public static final String KUNDEN_NACHNAME_QUERY_PARAM = "nachname"; public static final String KUNDEN_PLZ_QUERY_PARAM = "plz"; public static final String KUNDEN_EMAIL_QUERY_PARAM = "email"; @Context private UriInfo uriInfo; @Inject private KundenService ks; @Inject private BestellungService bs; @Inject private BestellungResource bestellungResource; @Inject private UriHelper uriHelper; @GET @Produces({ TEXT_PLAIN, APPLICATION_JSON + ";qs=0.75" }) @Path("version") public String getVersion() { return VERSION; } @GET @Path("{" + KUNDEN_ID_PATH_PARAM + ":[1-9][0-9]*}") public Response findKundeById(@PathParam(KUNDEN_ID_PATH_PARAM) Long id) { final AbstractKunde kunde = ks.findKundeById(id, FetchType.NUR_KUNDE); setStructuralLinks(kunde, uriInfo); final Response response = Response.ok(kunde) .links(getTransitionalLinks(kunde, uriInfo)) .build(); return response; } public void setStructuralLinks(AbstractKunde kunde, UriInfo uriInfo) { kunde.setBestellungUri(getUriBestellungen(kunde, uriInfo)); } private URI getUriBestellungen(AbstractKunde kunde, UriInfo uriInfo) { return uriHelper.getUri(KundeResource.class, "findBestellungenByKundeId", kunde.getId(), uriInfo); } public Link[] getTransitionalLinks(AbstractKunde kunde, UriInfo uriInfo) { final Link self = Link.fromUri(getUriKunde(kunde, uriInfo)) .rel(SELF_LINK) .build(); final Link list = Link.fromUri(uriHelper.getUri(KundeResource.class, uriInfo)) .rel(LIST_LINK) .build(); final Link add = Link.fromUri(uriHelper.getUri(KundeResource.class, uriInfo)) .rel(ADD_LINK) .build(); final Link update = Link.fromUri(uriHelper.getUri(KundeResource.class, uriInfo)) .rel(UPDATE_LINK) .build(); final Link remove = Link.fromUri(uriHelper.getUri(KundeResource.class, "deleteKunde", kunde.getId(), uriInfo)) .rel(REMOVE_LINK) .build(); return new Link[] {self, list, add, update, remove}; } public URI getUriKunde(AbstractKunde kunde, UriInfo uriInfo) { return uriHelper.getUri(KundeResource.class, "findKundeById", kunde.getId(), uriInfo); } @GET public Response findKunden(@QueryParam(KUNDEN_NACHNAME_QUERY_PARAM) @Pattern(regexp = AbstractKunde.NACHNAME_PATTERN, message = "{kunde.nachname.pattern}") String nachname, @QueryParam(KUNDEN_PLZ_QUERY_PARAM) @Pattern(regexp = "\\d{5}", message = "{adresse.plz}") String plz, @QueryParam(KUNDEN_EMAIL_QUERY_PARAM) @Email(message = "{kunde.email}") String email) { List<? extends AbstractKunde> kunden = null; AbstractKunde kunde = null; if (!Strings.isNullOrEmpty(nachname)) { kunden = ks.findKundenByNachname(nachname, FetchType.NUR_KUNDE); } else if (!Strings.isNullOrEmpty(plz)) { kunden = ks.findKundenByPLZ(plz); } else if (!Strings.isNullOrEmpty(email)) { kunde = ks.findKundeByEmail(email); } else { kunden = ks.findAllKunden(FetchType.NUR_KUNDE, OrderType.ID); } Object entity = null; Link[] links = null; if (kunden != null) { for (AbstractKunde k : kunden) { setStructuralLinks(k, uriInfo); } entity = new GenericEntity<List<? extends AbstractKunde>>(kunden) { }; links = getTransitionalLinksKunden(kunden, uriInfo); } else if (kunde != null) { entity = kunde; links = getTransitionalLinks(kunde, uriInfo); } return Response.ok(entity) .links(links) .build(); } private Link[] getTransitionalLinksKunden(List<? extends AbstractKunde> kunden, UriInfo uriInfo) { if (kunden == null || kunden.isEmpty()) { return null; } final Link first = Link.fromUri(getUriKunde(kunden.get(0), uriInfo)) .rel(FIRST_LINK) .build(); final int lastPos = kunden.size() - 1; final Link last = Link.fromUri(getUriKunde(kunden.get(lastPos), uriInfo)) .rel(LAST_LINK) .build(); return new Link[] {first, last}; } @GET @Path("/prefix/id/{id:[1-9][0-9]*}") public Collection<Long> findIdsByPrefix(@PathParam("id") String idPrefix) { final Collection<Long> ids = ks.findIdsByPrefix(idPrefix); return ids; } @GET @Path("/prefix/nachname/{nachname}") @Produces({ APPLICATION_JSON, TEXT_PLAIN + ";qs=0.75" }) public Collection<String> findNachnamenByPrefix(@PathParam("nachname") String nachnamePrefix) { final Collection<String> nachnamen = ks.findNachnamenByPrefix(nachnamePrefix); return nachnamen; } @GET @Path("{id:[1-9][0-9]*}/bestellungen") public Response findBestellungenByKundeId(@PathParam("id") Long kundeId) { final AbstractKunde kunde = ks.findKundeById(kundeId, FetchType.MIT_BESTELLUNGEN); final List<Bestellung> bestellungen = bs.findBestellungenByKunde(kunde); if (bestellungen != null) { for (Bestellung bestellung : bestellungen) { bestellungResource.setStructuralLinks(bestellung, uriInfo); } } final Response response = Response.ok(new GenericEntity<List<Bestellung>>(bestellungen) { }) .links(getTransitionalLinksBestellungen(bestellungen, kunde, uriInfo)) .build(); return response; } private Link[] getTransitionalLinksBestellungen(List<Bestellung> bestellungen, AbstractKunde kunde, UriInfo uriInfo) { if (bestellungen == null || bestellungen.isEmpty()) { return new Link[0]; } final Link self = Link.fromUri(getUriBestellungen(kunde, uriInfo)) .rel(SELF_LINK) .build(); final Link first = Link.fromUri(bestellungResource.getUriBestellung(bestellungen.get(0), uriInfo)) .rel(FIRST_LINK) .build(); final int lastPos = bestellungen.size() - 1; final Link last = Link.fromUri(bestellungResource.getUriBestellung(bestellungen.get(lastPos), uriInfo)) .rel(LAST_LINK) .build(); return new Link[] {self, first, last}; } @GET @Path("{id:[1-9][0-9]*}/bestellungenIds") @Produces({ APPLICATION_JSON, TEXT_PLAIN + ";qs=0.75", APPLICATION_XML + ";qs=0.5" }) public Response findBestellungenIdsByKundeId(@PathParam("id") Long kundeId) { final AbstractKunde kunde = ks.findKundeById(kundeId, FetchType.MIT_BESTELLUNGEN); final Collection<Bestellung> bestellungen = bs.findBestellungenByKunde(kunde); final int anzahl = bestellungen.size(); final Collection<Long> bestellungenIds = new ArrayList<>(anzahl); for (Bestellung bestellung : bestellungen) { bestellungenIds.add(bestellung.getId()); } return Response.ok(new GenericEntity<Collection<Long>>(bestellungenIds) { }) .build(); } @POST @Consumes({APPLICATION_JSON, APPLICATION_XML, TEXT_XML }) @Produces public Response createKunde(@Valid AbstractKunde kunde) { kunde.setId(KEINE_ID); final Adresse adresse = kunde.getAdresse(); if (adresse != null) { adresse.setKunde(kunde); } final Bankdaten bankdaten = kunde.getBankdaten(); if (bankdaten != null) { bankdaten.setKunde(kunde); } kunde = ks.createKunde(kunde); LOGGER.tracef("Kunde: %s", kunde); return Response.created(getUriKunde(kunde, uriInfo)) .build(); } @PUT @Consumes({ APPLICATION_JSON, APPLICATION_XML, TEXT_XML }) @Produces public void updateKunde(@Valid AbstractKunde kunde) { final AbstractKunde origKunde = ks.findKundeById(kunde.getId(), FetchType.NUR_KUNDE); LOGGER.tracef("Kunde vorher: %s", origKunde); origKunde.setValues(kunde); LOGGER.tracef("Kunde nachher: %s", origKunde); ks.updateKunde(origKunde); } @Path("{id:[0-9]+}") @DELETE @Produces public void deleteKunde(@PathParam("id") Long kundeId) { final AbstractKunde kunde = ks.findKundeById(kundeId, FetchType.NUR_KUNDE); ks.deleteKunde(kunde); } }